﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Citi.Import.Util;

namespace Citi.GocAttributes.Domain
{
    //public class FunctionImport : LevelParentImport<Function>
    //{
    //    protected override string IdColumnName { get { return "FUNCTION_ID"; } }
    //    protected override string DescriptionColumnName { get { return "DESCRIPTION"; } }
    //    protected override string DefinitionColumnName { get { return "DEFINITION"; } }
    //    protected override string ParentIdColumnName { get { return "PARENT_ID"; } }
    //    protected override string TreeLevelColumnName { get { return "Tree Level"; } }
    //    protected override string StatusColumnName { get { return "STATUS"; } }

    //    public ImportHistory Import(string path, DateTime referenceDate)
    //    {
    //        List<Error> erros = null;
    //        var functions = Conversion.ConvertFromExcel(GetDefinitions(), path, ref erros);

    //        //if (functions != null && functions.Any())
    //        //    SaveImport(functions, referenceDate);

    //        CacheFacade.Clear(typeof(Function));
    //        return ImportHistory.SaveHistory(erros, path);
    //    }
    //}

    public partial class Function
    {
        #region Import Validation

        private static readonly List<Definition<Function>> Definitions = new List<Definition<Function>>
            {
                new Definition<Function> { ModelProperty = x => x.Code, ColumnName = "FUNCTION_ID", CustomConversionMethod = ValidateFunctionId},
                new Definition<Function> { ModelProperty = x => x.Description, ColumnName = "DESCRIPTION"},
                new Definition<Function> { ModelProperty = x => x.Definition, ColumnName = "DEFINITION"},
                new Definition<Function> { ModelProperty = x => x.ParentId, ColumnName = "PARENT_ID", CustomConversionMethod = ValidateParentFunction},
                new Definition<Function> { ModelProperty = x => x.TreeLevel, ColumnName = "Tree Level"},
                new Definition<Function> { ModelProperty = x => x.Status, ColumnName = "STATUS"}
            };

        private static readonly List<Definition<Function>> DefinitionsWithoutParent = new List<Definition<Function>>
            {
                new Definition<Function> { ModelProperty = x => x.Code, ColumnName = "FUNCTION_ID", CustomConversionMethod = ValidateFunctionId},
                new Definition<Function> { ModelProperty = x => x.Description, ColumnName = "DESCRIPTION"},
                new Definition<Function> { ModelProperty = x => x.Definition, ColumnName = "DEFINITION"},
                new Definition<Function> { ModelProperty = x => x.TreeLevel, ColumnName = "Tree Level"},
                new Definition<Function> { ModelProperty = x => x.Status, ColumnName = "STATUS"}
            };

        private static object ValidateFunctionId(ref Function model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            var domain = CacheFacade.Get(new Function().SelectAllActive<Function>).FirstOrDefault(x => x.Code == value);

            if (domain != null)
            {
                if (!domain.Gocs.Any())
                    model = domain;
                else
                {
                    var description = fields[headers.IndexOf(Conversion.TransformColumnName("DESCRIPTION"))];
                    var definition = fields[headers.IndexOf(Conversion.TransformColumnName("DEFINITION"))];
                    var status = fields[headers.IndexOf(Conversion.TransformColumnName("STATUS"))];

                    if (domain.Description == description && domain.Definition == definition
                        && domain.Status == status)
                    {
                        model = domain;
                    }
                }
            }

            return value;
        }

        private static object ValidateParentFunction(ref Function model, string value, List<string> fields, ref string error, List<string> headers = null)
        {
            var id = fields[headers.IndexOf(Conversion.TransformColumnName("FUNCTION_ID"))];

            if (id == value)
                return Conversion.Validation.Validated;

            var domain = CacheFacade.Get(new Function().SelectAllActive<Function>).FirstOrDefault(x => x.Code == value);

            if (domain == null)
            {
                error = string.Format("PARENT ID '{0}' NOT FOUND", value);
                return Conversion.Validation.Failed;
            }

            model.Parent = domain;

            return Conversion.Validation.ManuallyValidated;
        }

        #endregion

        public static ImportHistory Import(string path, DateTime referenceDate)
        {
            List<Error> errors = null;
            var dataTable = Conversion.ReadExcel(path, ref errors, "Valid Values", 4);

            Save(DefinitionsWithoutParent, dataTable, ref errors, referenceDate);

            errors = null;
            Save(Definitions, dataTable, ref errors, referenceDate);

            return ImportHistory.SaveHistory(errors, path);

            //List<Error> erros = null;
            //var functions = Conversion.ConvertFromExcel(Definitions, path, ref erros);

            //if (functions != null && functions.Any())
            //    SaveImport(functions, referenceDate);

            //CacheFacade.Clear(typeof(Function));
            //return ImportHistory.SaveHistory(erros, path);
        }

        private static void Save(List<Definition<Function>> definitions, DataTable dataTable, ref List<Error> errors, DateTime referenceDate)
        {
            var functions = Conversion.Convert(definitions, dataTable, ref errors);

            if (functions != null && functions.Any())
            {
                functions.ForEach(x =>
                {
                    x.LastUpdate = DateTime.Now;

                    if (x.Id == 0)
                        x.ReferenceDate = referenceDate;
                });

                functions.First().Save(functions, 800);
            }

            CacheFacade.Clear(typeof(Function));
        }

        private static void SaveImport(List<Function> functions, DateTime referenceDate)
        {
            functions.ForEach(x =>
            {
                x.LastUpdate = DateTime.Now;

                if (x.Id == 0)
                    x.ReferenceDate = referenceDate;
            });

            var lastTreeLevel = functions.Max(x => x.TreeLevel);

            for (int level = 1; level <= lastTreeLevel; level++)
            {
                var functionsNextLevel = functions.Where(x => x.TreeLevel == level).ToList();

                if (level > 1)
                {
                    var functionsPrevious = functions.Where(x => x.TreeLevel == level - 1);
                    functionsNextLevel.ForEach(x =>
                        {
                            if (x.ParentId != 0) return;
                            var functionPrevious = functionsPrevious.FirstOrDefault(y => y.Code == x.Parent.Code);
                            if (functionPrevious == null) return;

                            x.Parent = functionPrevious;
                        });
                }

                if (functionsNextLevel.Any())
                    functionsNextLevel.First().Save(functionsNextLevel, 800);
            }
        }

        public Function SelectByCode(string code)
        {
            return SelectAll<Function>().FirstOrDefault(x => x.Code == code);
        }

        public Function SelectLastByCode(string code)
        {
            return SelectAll<Function>().OrderByDescending(x => x.ReferenceDate).FirstOrDefault(x => x.Code == code);
        }
    }
}